package cn.mw.cmdb.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.enums.RelatedSelectEnum;
import cn.mw.cmdb.exception.CompoundException;
import cn.mw.cmdb.exception.DateFormatException;
import cn.mw.cmdb.param.TableSearchParam;
import cn.mw.cmdb.service.ModelManage;
import cn.mw.cmdb.view.InstanceListViewConverter;
import cn.mw.components.mongodb.entity.SearchParam;
import cn.mw.microMonitorCommon.api.cmdb.TableIdEnum;
import cn.mw.microMonitorCommon.api.common.MwModuleFieldApi;
import cn.mw.microMonitorCommon.api.user.MwUserApi;
import cn.mw.microMonitorCommon.entity.common.FieldConditionDto;
import cn.mw.microMonitorCommon.entity.common.MwModuleFiledDto;
import cn.mw.microMonitorCommon.entity.common.MwModuleInfoDto;
import cn.mw.microMonitorCommon.entity.common.MwTableAndFiledDto;
import cn.mw.microMonitorCommon.enums.MwAbutmentModuleEnum;
import cn.mw.microMonitorCommon.param.MwModuleFieldParam;
import cn.mw.microMonitorCommon.util.SpringUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.mw.cmdb.entity.InstanceInfo.SearchPrefix;
import static cn.mw.cmdb.util.MwCMDBMongoDBApi.getSearchParamList;
import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;

@DubboService(group = "CMDB")
@Service
@Slf4j
public class MwCmdbFieldApiImpl implements MwModuleFieldApi {
    public static final String ID = "cmdbFieldApiImpl";
    public static final String ExtSingleIdKey = "extSingle";
    private static final String mwInstanceIdKey = "instanceId";

    private static final String idKey = "id";

    private static final String relationIdKey = "relationId";
    //关联查询字段:负责人,机构,用户组,监控服务器,轮询引擎
    private static final List<String> disablePropertyIdList = Arrays.asList(PropertyTypeStruct.ID, PropertyTypeLayoutCabinet.ID, PropertyTypeLayoutRoom.ID, PropertyTypeQRCode.ID);
    private static final List<String> disablePropertyCatologNameList = Arrays.asList("机房布局", "机柜布局", "U位管理");


    private ModelManage modelManage;

    private CmdbServiceManage cmdbServiceManage;
    @DubboReference(check = false, mock = "true", timeout = 12000)
    private MwUserApi userApi;

    public MwCmdbFieldApiImpl(ModelManage modelManage, CmdbServiceManage cmdbServiceManage) {
        this.modelManage = modelManage;
        this.cmdbServiceManage = cmdbServiceManage;
    }


    @Override
    public List<MwModuleInfoDto> getAbutmentModuleFiledInfo() {
        List<MwModuleInfoDto> result = new ArrayList<>();
        try {
            MwModuleInfoDto mwModuleInfoDto = new MwModuleInfoDto();
            mwModuleInfoDto.setModuleName(MwAbutmentModuleEnum.CMDB.getModuleName());
            List<MwTableAndFiledDto> tableDtos = new ArrayList<>();
            MwTableAndFiledDto mwTableAndFiledDto = new MwTableAndFiledDto();
            mwTableAndFiledDto.setTableName(InstanceInfo.class.getAnnotation(Document.class).value());
            // 获取所有数据库字段
            List<MwModuleFiledDto> filedDtos = getMwModuleFiledList();
            List<MwModuleFiledDto> list = filedDtos.stream().collect(Collectors.toMap(item -> item.getFiledName() + "_" + item.getEntityName(),
                    obj -> obj, (k1, k2) -> k1)).values().stream().toList();
            mwTableAndFiledDto.setFiledDtos(list);
            tableDtos.add(mwTableAndFiledDto);
            mwModuleInfoDto.setTableDtos(tableDtos);
            result.add(mwModuleInfoDto);
        } catch (Exception e) {
            throw new CompoundException();
        }
        return result;
    }

    @SneakyThrows
    @Override
    public Object getAbutmentModuleDataInfo(MwModuleFieldParam mwModuleFieldParam) {
        List<Map> instanceResultMap = new ArrayList<>();
        List<String> fieldNames = mwModuleFieldParam.getFieldNames();
//        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
//        List<InstanceInfoExtend> instanceInfoList = new ArrayList<>();
        ModelPropertyServiceImpl propertyService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
        List<PropertyInfo> allModelByListShowProperty = propertyService.getAllModelPropertyList();
        Map<String, PropertyInfo> allPropertyMap = allModelByListShowProperty.stream().collect(Collectors.toMap(s -> s.getId(), s -> s, (
                value1, value2) -> {
            return value2;
        }));
        try {
            List<FieldConditionDto> conditionDtoList = mwModuleFieldParam.getConditionDtoList();
//            InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
//            SearchParam searchParamList = getSearchParamList(conditionDtoList,allPropertyMap);
            SearchParam searchParamList = getSearchParamList(conditionDtoList);

            TableSearchParam tableSearchParam = new TableSearchParam();
            BeanUtil.copyProperties(searchParamList, tableSearchParam, CopyOptions.create().setIgnoreNullValue(true));
            //通用实例字段
            tableSearchParam.setTableId(TableIdEnum.commonInstance.getCode());
            tableSearchParam.setShowAllField(true);
            TableHeaderAndDataManage dataManage = SpringUtils.getBean(TableHeaderAndDataManage.class);
            List<Map> list = (List<Map>) dataManage.listTableData(tableSearchParam);
//            List<Map> maps = dateFormatConvert(instanceInfoList);
            instanceResultMap = getInstanceResultToMap(list, fieldNames, allPropertyMap);
        } catch (Exception e) {
            throw new CompoundException();
        }
        return instanceResultMap;
    }

    private List<Map> getInstanceResultToMap(List<Map> listMap, List<String> fieldNames, Map<String, PropertyInfo> allPropertyMap) throws Exception {
        List<Map> mapsList = new ArrayList<>();
        for (Map map : listMap) {
            Map convertMap = new HashMap();
            Map m = (Map) map.get(SearchPrefix);
            if (m != null) {
                map.putAll(m);
            }
            map.forEach((k, v) -> {
                if (fieldNames.contains(k)) {
                    //根据模型数据类型，转换数据显示
                    if (allPropertyMap != null && allPropertyMap.containsKey(k) && v != null) {
                        PropertyInfo propertyInfo = allPropertyMap.get(k);
                        String typeId = propertyInfo.getPropertyTypeRef().getTypeId();
                        PropertyType propertyType = PropertyTypeManage.getPropertyType(typeId);
                        Map<String, Object> contextParam = propertyInfo.getPropertyTypeRef().getContext();
                        if (contextParam != null) {
                            contextParam.put(InstanceListViewConverter.dataListMap, map);
                        }
                        Object obj = propertyType.exportValue(v, contextParam);
                        String relationId = "";
                        String key = "";
                        if (ExtSingleIdKey.equals(typeId)) {
                            key = k + "Id";
                            if (v instanceof Map) {
                                Map ms = (Map) v;
                                relationId = strValueConvert(ms.get(relationIdKey));
                            }
                            convertMap.put(key, relationId);
                        }
                        convertMap.put(mwInstanceIdKey, map.get(idKey));
                        convertMap.put(k, obj);
                    }
                }
            });
            if (!CollectionUtil.isEmpty(convertMap)) {
                mapsList.add(convertMap);
            }
        }
        return mapsList;
    }

    /**
     * 资产实例数据时间格式转换
     */
    private List<Map> dateFormatConvert(List<InstanceInfoExtend> list) {
        List<Map> listMap = new ArrayList<>();
        try {
            for (InstanceInfoExtend instance : list) {
                Map ms = new HashMap();
                //获取类字段
                Field[] declaredFields = instance.getClass().getDeclaredFields();
                //获取父类字段
                Field[] parentDeclaredFields = instance.getClass().getSuperclass().getDeclaredFields();
                Field[] declaredFieldList = Stream.concat(Arrays.stream(declaredFields), Arrays.stream(parentDeclaredFields)).toArray(Field[]::new);
                for (Field field : declaredFieldList) {
                    field.setAccessible(true); // 设置属性可访问 // 判断属性类型是否为Date类型
                    String key = field.getName();
                    Object value = null;
                    if (field.getType() == Date.class) {
                        // 对Date类型属性进行时间格式转换
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        Date date = (Date) field.get(instance);
                        // 获取属性值
                        if (date != null) {
                            value = sdf.format(date);

                        }
                    } else { // 其他类型的属性直接输出值
                        value = field.get(instance);
                    }
                    ms.put(key, value);
                }
                listMap.add(ms);
            }
        } catch (Exception e) {
            throw new DateFormatException();
        }
        return listMap;
    }


    private List<MwModuleFiledDto> getMwModuleFiledList() throws Exception {
        ModelPropertyServiceImpl propertyService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
        List<PropertyInfo> allModelByListShowProperty = propertyService.getAllModelByListShowProperty();
        List<MwModuleFiledDto> dtoList = new ArrayList<>();
        for (PropertyInfo propertyInfo : allModelByListShowProperty) {
            String typeId = propertyInfo.getPropertyTypeRef().getTypeId();
            //不适用报表展示的属性类型
            if (!disablePropertyIdList.contains(typeId) && !disablePropertyCatologNameList.contains(propertyInfo.getPropertyCatologName())) {
                MwModuleFiledDto mwModuleFiledDto = new MwModuleFiledDto();
                mwModuleFiledDto.setFiledName(propertyInfo.getId());
                mwModuleFiledDto.setEntityName(propertyInfo.getId());
                mwModuleFiledDto.setFiledDesc(propertyInfo.getName());
                dtoList.add(mwModuleFiledDto);
            }
        }
        List<MwModuleFiledDto> collect = dtoList.stream().distinct().collect(Collectors.toList());
        return collect;
    }


    private void relationFiledConvert(String filedName) {
        RelatedSelectEnum relatedFieldInfo = RelatedSelectEnum.getRelatedFieldInfo(filedName);
        switch (relatedFieldInfo) {
            case userNames:
                break;
            case groupNames:
                break;
            case orgNames:
                break;
            case pollingEngineName:
                break;
            case monitorServerName:
                break;
        }
    }

}
